/*
 *  Copyright 2016 http://www.kedacomframework.org
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *
 */

package com.kedacom.ctsp.authz.oauth2.service;


import com.google.common.collect.Lists;
import com.kedacom.ctsp.authority.entity.*;
import com.kedacom.ctsp.authority.service.*;
import com.kedacom.ctsp.authority.vo.ResourceVO;
import com.kedacom.ctsp.authz.exception.UnauthorizedException;
import com.kedacom.ctsp.authz.oauth2.core.vo.*;
import com.kedacom.ctsp.authz.oauth2.entity.AccessToken;
import com.kedacom.ctsp.authz.oauth2.entity.Client;
import com.kedacom.ctsp.lang.mapper.BeanMapper;
import com.kedacom.ctsp.orm.param.TermEnum;
import com.kedacom.ctsp.web.controller.message.ResponseMessage;
import com.kedacom.ctsp.web.entity.TreeSupportBean;
import com.kedacom.ctsp.web.entity.page.PagerResult;
import com.kedacom.ctsp.web.entity.param.QueryParamEntity;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static com.kedacom.ctsp.web.controller.message.ResponseMessage.ok;

/**
 * 获取权限信息
 *
 * @author fenghaiju
 */
@Service("oauthResourceService")
public class OAuth2ResourceServiceImpl implements OAuthResourceService {

    @Autowired
    private UserService userService;
    @Autowired
    private DepartmentService departmentService;
    @Autowired
    private PersonService personService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private ResourceService resourceService;
    @Autowired
    private ClientService clientService;
    @Autowired
    private AccessTokenService accessTokenService;
    @Autowired
    private ResourceSettingRelationService resourceSettingRelationService;

    /**
     * 根据accessToken获取用户信息
     *
     * @param param
     * @return
     */
    @Override
    public PagerResult<PlainUser> queryUser(ClientQueryParam param) {
        clientService.validateClient(param.getClientId(), param.getClientSecret());

        return userService.selectPager(param).convertTo(e -> BeanMapper.deepMap(e, PlainUser.class));
    }

    /**
     * 根据accessToken获取部门信息
     *
     * @param param
     * @return
     */
    @Override
    public PagerResult<PlainDepartment> queryDepartment(ClientQueryParam param) {
        clientService.validateClient(param.getClientId(), param.getClientSecret());

        return departmentService.selectPager(param)
                .convertTo(e -> BeanMapper.deepMap(e, PlainDepartment.class));
    }


    /**
     * 根据accessToken获取人员信息
     *
     * @param param
     * @return
     */
    @Override
    public PagerResult<PlainPerson> queryPerson(ClientQueryParam param) {
        clientService.validateClient(param.getClientId(), param.getClientSecret());

        return personService.selectPager(param)
                .convertTo(e -> BeanMapper.deepMap(e, PlainPerson.class));
    }

    /**
     * 根据accessToken获取角色信息
     *
     * @param param
     * @return
     */
    @Override
    public PagerResult<PlainRole> queryRole(ClientQueryParam param) {
        clientService.validateClient(param.getClientId(), param.getClientSecret());

        param.and(Role.CLIENTSIGN, param.getClientId());

        return roleService.selectPager(param)
                .convertTo(e -> BeanMapper.deepMap(e, PlainRole.class));
    }

    /**
     * 根据accessToken获取角色信息
     *
     * @param param
     * @return
     */
    @Override
    public PagerResult<PlainRole> queryRoleByUser(UserQueryParam param) {
        clientService.validateClient(param.getClientId(), param.getClientSecret());

        param.and(Role.CLIENTSIGN, param.getClientId());

        return roleService.selectPager(param)
                .convertTo(e -> BeanMapper.deepMap(e, PlainRole.class));
    }


    @Override
    public PagerResult<PlainResourceSetting> queryResourceSetting(ClientQueryParam param) {
        clientService.validateClient(param.getClientId(), param.getClientSecret());
        param.and(ResourceSettingRelation.RESOURCE_CLIENT_SIGN, param.getClientId());

        return resourceSettingRelationService.selectPager(param)
                .convertTo(e -> BeanMapper.deepMap(e, PlainResourceSetting.class));
    }


    /**
     * 密码修改
     *
     * @param userId
     * @param oldPassword
     * @param newPassword
     * @return
     */
    @Override
    public String updatePassword(String userId, String oldPassword, String newPassword) {
        return userService.updatePassword(userId, oldPassword, newPassword);
    }

    @Override
    public ResponseMessage<List<ResourceVO>> listMyAsTree(ClientQueryParam param) {

        clientService.validateClient(param.getClientId(), param.getClientSecret());

        param.and(Resource.CLIENT_SIGN, param.getClientId());
        param.setPaging(false);
        Set<String> resourceIds = currentResourceIds(param);
        if (CollectionUtils.isNotEmpty(resourceIds)) {
            param.and(Resource.ID, TermEnum.in, resourceIds);
            List<Resource> resources = resourceService.selectAsTree(param);
            List<ResourceVO> resourceVOList = resources.stream().map(r -> {
                ResourceVO resourceVO = resourceService.createInstance(ResourceVO.class);
                resourceVO.convertFrom(r);
                return resourceVO;
            }).collect(Collectors.toList());
            ResponseMessage<List<ResourceVO>> result = ok(resourceVOList);
            result.exclude(TreeSupportBean.class, TreeSupportBean.PARENT);
            return result;
        } else {
            return ok(Lists.newArrayList());
        }
    }

    /**
     * 当前登录用户拥有的资源ids
     *
     * @return
     */
    private Set<String> currentResourceIds(ClientQueryParam param) {
        List<Resource> myResources = resourceService.select(param);
        Set<String> resourceIds = myResources.stream().map(Resource::getId).collect(Collectors.toSet());
        return resourceIds;
    }

    /**
     * 获取客户端列表
     *
     * @param param
     * @return
     */
    @Override
    public ResponseMessage<PagerResult<PlainClient>> clientList(QueryParamEntity param) {
        PagerResult<PlainClient> pagerResult = new PagerResult();
        List<Client> clients = clientService.select(param);
        List<PlainClient> plainClients = new ArrayList<>();
        clients.stream().forEach(e -> {
            plainClients.add(BeanMapper.deepMap(e, PlainClient.class));
        });
        pagerResult.setData(plainClients);
        pagerResult.setTotal((long) pagerResult.getData().size());
        return ResponseMessage.ok(pagerResult);
    }

    /**
     * 通过用户获取用户的项目
     *
     * @param param
     * @return
     */
    @Override
    public List<PlainClient> getUserClient(UserQueryParam param) {
        accessTokenService.checkAccessToken(param);
        clientService.validateClient(param.getClientId(), param.getClientSecret());
        AccessToken auth2AccessEntity = accessTokenService.getTokenByAccessToken(param.getAccessToken());
        if (null == auth2AccessEntity) {
            throw new UnauthorizedException();
        }
        User user = userService.get(auth2AccessEntity.getOwnerId());
        List<Client> clients = clientService.getUserClient(user.getId());
        List<PlainClient> plainClientList = new ArrayList<>();
        clients.stream().forEach(client -> {
            plainClientList.add(BeanMapper.deepMap(client, PlainClient.class));
        });
        return plainClientList;
    }

    @Override
    public PagerResult<Department> queryDept(String pid, ClientQueryParam param) {

        clientService.validateClient(param.getClientId(), param.getClientSecret());

        if (StringUtils.isNotBlank(pid)) {
            param.and(Department.PARENT_ID, pid);
            return departmentService.selectAllChildNodePager(pid, param);
        }
        return departmentService.selectPager(param);
    }

    @Override
    public PagerResult<Department> queryDeptByUser(String pid, UserQueryParam param) {

        accessTokenService.checkAccessToken(param);
        clientService.validateClient(param.getClientId(), param.getClientSecret());

        if (StringUtils.isNotBlank(pid)) {
            param.and(Department.PARENT_ID, pid);
            return departmentService.selectAllChildNodePager(pid, param);
        }

        return departmentService.selectPager(param);
    }

    @Override
    public List<Department> queryDeptAsTree(String pid, ClientQueryParam param) {
        clientService.validateClient(param.getClientId(), param.getClientSecret());

        param.setPaging(false);
        if (StringUtils.isNotBlank(pid)) {
            return departmentService.selectAsTree(pid, param);
        }

        //获取部门树
        return departmentService.selectAsTree(param);

    }

    @Override
    public List<Department> queryDeptAsTreeByUser(String pid, UserQueryParam param) {

        accessTokenService.checkAccessToken(param);
        return queryDeptAsTree(pid, param);
    }


    @Override
    public PagerResult<Resource> queryResource(String pid, ClientQueryParam param) {
        clientService.validateClient(param.getClientId(), param.getClientSecret());

        param.and(Resource.CLIENT_SIGN, param.getClientId());

        if (StringUtils.isNotBlank(pid)) {
            param.and(Department.PARENT_ID, pid);
            return resourceService.selectAllChildNodePager(pid, param);
        }
        return resourceService.selectPager(param);
    }


    @Override
    public PagerResult<Resource> queryResourceByUser(String pid, UserQueryParam param) {
        accessTokenService.checkAccessToken(param);
        return queryResource(pid, param);
    }

    @Override
    public List<Resource> queryResourceAsTreeByUser(String pid, UserQueryParam param) {
        accessTokenService.checkAccessToken(param);
        return queryResourceAsTree(pid, param);
    }

    @Override
    public List<Resource> queryResourceAsTree(String pid, ClientQueryParam param) {
        clientService.validateClient(param.getClientId(), param.getClientSecret());

        param.and(Resource.CLIENT_SIGN, param.getClientId());
        param.setPaging(false);

        Set<String> resourceIds = currentResourceIds(param);
        if (CollectionUtils.isEmpty(resourceIds)) {
            return Lists.newArrayList();
        }
        param.and(Resource.ID, TermEnum.in, resourceIds);

        if (StringUtils.isNotBlank(pid)) {
            return resourceService.selectAsTree(pid, param);
        }

        //获取部门树
        return resourceService.selectAsTree(param);
    }
}
